{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## _*FermionicOperator and qubit mapping*_\n",
    "\n",
    "When we compute a FermionicOperator in Qiskit Chemistry it needs to be converted to a qubit operator to run on the simulator or real device. The FermionicOperator is built from electron integrals where electrons behave anti-symmetrically under swap. Qubits however do not exhibit this behavior and hence a mapping is needed to ensure that this is accounted for.\n",
    "\n",
    "Here we have the jordan wigner mapping, the bravyi-kitaev mapping and a parity."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "from qiskit_nature.second_q.drivers import PySCFDriver\n",
    "from qiskit_nature.second_q.transformers import FreezeCoreTransformer\n",
    "from qiskit_nature.second_q.mappers import ParityMapper, JordanWignerMapper, BravyiKitaevMapper\n",
    "from qiskit_nature.second_q.algorithms import GroundStateEigensolver\n",
    "\n",
    "from qiskit_algorithms import NumPyMinimumEigensolver\n",
    "\n",
    "from qiskit_algorithms.optimizers import SLSQP\n",
    "\n",
    "from qiskit_nature.second_q.circuit.library import HartreeFock, UCCSD\n",
    "from qiskit_algorithms import VQE\n",
    "from qiskit.primitives import Estimator"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "driver = PySCFDriver(atom='H .0 .0 .0; H .0 .0 0.74279')\n",
    "molecule = driver.run()\n",
    "\n",
    "mappers = [\n",
    "    ('Jordan-Wigner', JordanWignerMapper()),\n",
    "    ('Parity', ParityMapper(num_particles=molecule.num_particles)),\n",
    "    ('Bravyi-Kitaev', BravyiKitaevMapper())\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Jordan-Wigner:\n",
      "--- Number of qubits needed: 4, Number of paulis: 15\n",
      "--- NumPyMinimumEigensolver result: -1.1372534438864932 Ha\n",
      "--- VQE result: -1.1372534438281199 Ha\n",
      "Parity:\n",
      "--- Number of qubits needed: 2, Number of paulis: 5\n",
      "--- NumPyMinimumEigensolver result: -1.1372534438864927 Ha\n",
      "--- VQE result: -1.13725344382852 Ha\n",
      "Bravyi-Kitaev:\n",
      "--- Number of qubits needed: 4, Number of paulis: 15\n",
      "--- NumPyMinimumEigensolver result: -1.1372534438864927 Ha\n",
      "--- VQE result: -1.137253443827503 Ha\n"
     ]
    }
   ],
   "source": [
    "transformer = FreezeCoreTransformer()\n",
    "molecule = transformer.transform(molecule)\n",
    "hamiltonian = molecule.hamiltonian.second_q_op()\n",
    "\n",
    "for name, mapper in mappers:\n",
    "    print(f'{name}:')\n",
    "\n",
    "    qubit_op = mapper.map(hamiltonian)\n",
    "    print(f'--- Number of qubits needed: {qubit_op.num_qubits}, Number of paulis: {qubit_op.size}')\n",
    "\n",
    "    algo = NumPyMinimumEigensolver()\n",
    "    algo.filter_criterion = molecule.get_default_filter_criterion()\n",
    "    solver = GroundStateEigensolver(mapper, algo)\n",
    "    result = solver.solve(molecule)\n",
    "    print(f'--- NumPyMinimumEigensolver result: {result.total_energies[0]} Ha')\n",
    "\n",
    "    optimizer = SLSQP(maxiter=10000, ftol=1e-9)\n",
    "    ansatz = UCCSD(\n",
    "        molecule.num_spatial_orbitals,\n",
    "        molecule.num_particles,\n",
    "        mapper,\n",
    "        initial_state=HartreeFock(\n",
    "            molecule.num_spatial_orbitals,\n",
    "            molecule.num_particles,\n",
    "            mapper,\n",
    "        ),\n",
    "    )\n",
    "    vqe = VQE(Estimator(), ansatz, optimizer)\n",
    "    vqe.initial_point = [0] * ansatz.num_parameters\n",
    "    algo = GroundStateEigensolver(mapper, vqe)\n",
    "    result = algo.solve(molecule)\n",
    "    print(f'--- VQE result: {result.total_energies[0]} Ha')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "qiskit==1.1.0\n",
      "qiskit-aer==0.14.2\n",
      "qiskit-algorithms==0.3.0\n",
      "qiskit-ibm-runtime==0.25.0\n",
      "qiskit-machine-learning==0.7.2\n",
      "qiskit-nature==0.7.2\n",
      "qiskit-nature-pyscf==0.4.0\n",
      "qiskit-qasm3-import==0.5.0\n",
      "qiskit-transpiler-service==0.4.5\n"
     ]
    }
   ],
   "source": [
    "! pip freeze | grep qiskit"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.14"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
